package com.x.provider.general.service.gift;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.x.core.utils.BeanUtil;
import com.x.kafka.MqTemplate;
import com.x.provider.api.general.constants.GeneralEventTopic;
import com.x.provider.api.general.model.dto.gift.GiftDTO;
import com.x.provider.api.general.model.dto.gift.GiftRewardReqDTO;
import com.x.provider.api.general.model.event.GiftRewardEvent;
import com.x.provider.api.oss.service.OssRpcService;
import com.x.provider.api.pay.enums.*;
import com.x.provider.api.pay.model.dto.CreateOrderDTO;
import com.x.provider.api.pay.model.dto.CreateOrderItemDTO;
import com.x.provider.api.pay.model.dto.CreateTransactionDTO;
import com.x.provider.api.pay.service.PayRpcService;
import com.x.provider.general.mapper.GiftCategoryMapper;
import com.x.provider.general.mapper.GiftMapper;
import com.x.provider.general.model.domain.gift.Gift;
import com.x.provider.general.model.domain.gift.GiftCategory;
import com.x.provider.general.model.query.gift.GiftCategoryQuery;
import com.x.provider.general.model.query.gift.GiftQuery;
import org.springframework.stereotype.Service;

import java.util.Arrays;
import java.util.List;
import java.util.Map;

/**
 * @author: liushenyi
 * @date: 2022/10/27/16:16
 */
@Service
public class GiftServiceImpl implements GiftService{

    private final PayRpcService payRpcService;
    private final GiftMapper giftMapper;
    private final OssRpcService ossRpcService;
    private final MqTemplate mqTemplate;
    private final GiftCategoryMapper giftCategoryMapper;

    public GiftServiceImpl(PayRpcService payRpcService,
                           GiftMapper giftMapper,
                           OssRpcService ossRpcService,
                           MqTemplate mqTemplate,
                           GiftCategoryMapper giftCategoryMapper){
        this.payRpcService = payRpcService;
        this.giftMapper = giftMapper;
        this.ossRpcService = ossRpcService;
        this.mqTemplate = mqTemplate;
        this.giftCategoryMapper = giftCategoryMapper;
    }

    @Override
    public void giftReward(GiftRewardReqDTO request) {
        final Gift gift = get(request.getGiftId());
        final CreateTransactionDTO createTransactionDTO = prepare(gift, request);
        payRpcService.transaction(createTransactionDTO);
        mqTemplate.send(GeneralEventTopic.TOPIC_NAME_GIFT_REWARD, request.getToCustomerId().toString(), prepareGiftRewardEvent(gift, request));
    }

    @Override
    public List<Gift> listGift() {
        return list(GiftQuery.builder().build());
    }

    @Override
    public List<GiftCategory> listGiftCategory() {
        return list(GiftCategoryQuery.builder().build());
    }

    public Gift get(Long id){
        return get(GiftQuery.builder().id(id).build());
    }

    private Gift get(GiftQuery giftQuery){
        return giftMapper.selectOne(build(giftQuery));
    }

    private List<Gift> list(GiftQuery giftQuery){
        return giftMapper.selectList(build(giftQuery));
    }

    private LambdaQueryWrapper<Gift> build(GiftQuery giftQuery){
        final LambdaQueryWrapper<Gift> queryWrapper = new LambdaQueryWrapper<>();
        if (giftQuery.getId() != null){
            queryWrapper.eq(Gift::getId, giftQuery.getId());
        }
        return queryWrapper;
    }

    private List<GiftCategory> list(GiftCategoryQuery query){
        return giftCategoryMapper.selectList(build(query));
    }

    private LambdaQueryWrapper<GiftCategory> build(GiftCategoryQuery giftCategoryQuery){
        final LambdaQueryWrapper<GiftCategory> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.orderByAsc(GiftCategory::getDisplayOrder);
        return queryWrapper;
    }

    private CreateTransactionDTO prepare(Gift gift, GiftRewardReqDTO request){
        Long fromCoin = gift.getPrice() * request.getGiftNum().longValue();

        CreateOrderItemDTO createOrderItemDTO = CreateOrderItemDTO.builder()
                .customerId(request.getCustomerId())
                .discountAmount(0L).originalProductCost(fromCoin).payProductCost(fromCoin).productId(gift.getId()).productType(ProductTypeEnum.GIFT.getValue())
                .quantity(request.getGiftNum().longValue())
                .build();
        CreateOrderDTO createOrderDTO = CreateOrderDTO.builder()
                .currencyCode(CurrencyEnum.COIN.getValue())
                .customerId(request.getCustomerId())
                .orderItemList(Arrays.asList(createOrderItemDTO))
                .orderTotal(createOrderItemDTO.getPayProductCost())
                .payMethodId(PayMethodEnum.COIN.getValue())
                .productType(ProductTypeEnum.GIFT.getValue())
                .paymentStatus(PaymentStatusEnum.USERPAYING.getValue())
                .orderStatus(OrderStatusEnum.PENDING.getValue())
                .build();
        CreateTransactionDTO result = CreateTransactionDTO.builder()
                .fromCustomerId(request.getCustomerId())
                .fromCoin(fromCoin)
                .toCustomerId(request.getToCustomerId())
                .toCoin(gift.getToCoin() * request.getGiftNum().longValue())
                .toRice(gift.getToRice() * request.getGiftNum().longValue())
                .transactionType(TransactionTypeEnum.REWARD_GIFT.getValue())
                .order(createOrderDTO)
                .build();
        return result;
    }

    private GiftRewardEvent prepareGiftRewardEvent(Gift gift, GiftRewardReqDTO request){
        GiftDTO giftDTO = BeanUtil.prepare(gift, GiftDTO.class);
        final Map<String, String> objectBrowserUrlMap = ossRpcService.listObjectBrowseUrl(Arrays.asList(gift.getIconId(), gift.getAnimationId())).getData();
        giftDTO.setAnimationUrl(objectBrowserUrlMap.get(giftDTO.getAnimationId()));
        giftDTO.setIconUrl(objectBrowserUrlMap.get(giftDTO.getIconId()));
        return GiftRewardEvent.builder()
                .gift(giftDTO)
                .customerId(request.getCustomerId())
                .giftId(request.getGiftId())
                .giftNum(request.getGiftNum())
                .originEnum(request.getOriginEnum())
                .toCustomerId(request.getToCustomerId())
                .build();
    }
}
